"""
Findme server

1. add new user
2. upload picture for user
3. get next match for user
4. indicate interest

Communication protocol between clients and servers:

Client and server agree on pre-defined integer codes
to represent each API call.

The client first sends the API integer code, followed
by the API arguments. Each argument is sent in two parts:
an integer (4-byte) value that indicates how many bytes
long the argument is, followed by the actual argument.

The client marshals each argument into a byte array,
and the server unmarshals the argument in the exact
opposite manner.
"""

import socket
import struct
import signal
import sys
import logging

PORT = 9876
CONNECTIONS = 5

import sockets.utils as sock_utils
from api import add_user

# client and server both use these codes
class APICodes:
    ADD_USER = 1
    INDICATE_INTEREST = 2
    GETNEXTMATCH = 3
    SUCCESS = 4
    ERROR = 5


def handle_add_user_request( db, clientsocket ):
    username = sock_utils.read_string( clientsocket )
    password_hash = sock_utils.read_string( clientsocket )
    email = sock_utils.read_string( clientsocket )
    picture_url = None
    has_picture = sock_utils.read_boolean( clientsocket )
    if has_picture:
        contents = sock_utils.read_string( clientsocket )
        ext = sock_utils.read_string( clientsocket )
        # save picture on disk
        picture_url = save_image( contents, ext )
    userid = add_user( db, username, password_hash,
                       picture_url=picture_url,
                       email=email if email else None )
    sock_utils.write_integer( clientsocket, userid )
    sock_utils.write_integer( clientsocket, APICodes.SUCCESS )


def handle_interest_indication( db, clientsocket ):
    pass


def handle_get_next_match( db, clientsocket ):
    pass


def handle_request( db, clientsocket ):

    api_code = sock_utils.read_integer( clientsocket )
    if api_code == APICodes.ADD_USER:
        handle_add_user_request( db, clientsocket )
    elif api_code == APICodes.INDICATE_INTEREST:
        handle_interest_indication( db, clientsocket )
    elif api_code == APICodes.GETNEXTMATCH:
        handle_get_next_match( db, clientsocket )
    else:
        raise Exception( "received unknown API code from client: %s" % ( api_code, ) )


if __name__ == '__main__':

    shutdown = False
    logger = logging.getLogger('findmeserver')
    serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serversocket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
    serversocket.bind( ( 'localhost', PORT ) )
    serversocket.listen(CONNECTIONS)

    def int_handler( signum, frame ):
        print >> sys.stderr, "received signal %s; shutting down server..." % ( signum, )
        shutdown = True

    signal.signal( signal.SIGQUIT, int_handler )
    signal.signal( signal.SIGINT, int_handler )

    print >> sys.stderr, "findme server up and running on port %s ..." % ( PORT, )
    while not shutdown:
        # accept connections from outside
        (clientsocket, address) = serversocket.accept()
        handle_request(None, clientsocket)

    serversocket.close()
